#ifndef _RECEIVE_CALLBACK_H_
#define _RECEIVE_CALLBACK_H_

#include <moying_comm_lib/moying_commu_base.h>
#include "google/protobuf/descriptor.h"

namespace moying
{
namespace communication
{
    class CallbackBase
    {
        public:
            virtual void processData(const bytes_ptr data)
            {
                printf("Error calling processData directly in CallbackBase");
            }
    };
    typedef std::shared_ptr<CallbackBase> CallbackBasePtr;

    template<typename T>
    class SubscribeCallback: public CallbackBase
    {
        public:
            SubscribeCallback(std::function<void(const T&)> sub_cb)
            {
                sub_cb_ = sub_cb;
            }
            void processData(const bytes_ptr data)
            {
                sub_cb_(getProtobufMessage<T>(data));
            }
        private:
            std::function<void(const T&)> sub_cb_;
    };

    class RequestCallbackBase
    {
        public:
            virtual void processService(const std::string &request, const std::string &response)
            {
                printf("Error calling processService directly in RequestCallbackBase");
            }
    };
    typedef std::shared_ptr<RequestCallbackBase> RequestCallbackBasePtr;

    template<typename REQ, typename RES>
    class RequestCallback: public RequestCallbackBase
    {
        public:
            RequestCallback(std::function<void(const REQ&, const RES&)> req_cb)
            {
                req_cb_ = req_cb;
            }
            void processService(const std::string &request, const std::string &response)
            {
                REQ req;
                if(!req.ParseFromArray(request.data(), request.size()))
                {
                    printf("%s\n","sub_recv_func parse protobuf failed in getProtobufMessage()");
                }
                RES res;
                if(!res.ParseFromArray(response.data(), response.size()))
                {
                    printf("%s\n","sub_recv_func parse protobuf failed in getProtobufMessage()");
                }
                req_cb_(req, res);
            }
        private:
            std::function<void(const REQ&, const RES&)> req_cb_;
    };

    class ReplyCallbackBase
    {
        public:
            virtual void processService(const bytes_ptr &request, bytes_ptr &response)
            {
                printf("Error calling processService directly in ReplyCallbackBase");
            }
    };
    typedef std::shared_ptr<ReplyCallbackBase> ReplyCallbackBasePtr;

    template<typename REQ, typename RES>
    class ReplyCallback: public ReplyCallbackBase
    {
        public:
            ReplyCallback(std::function<void(const REQ&, RES&)> rep_cb)
            {
                rep_cb_ = rep_cb;
            }
            void processService(const bytes_ptr &request, bytes_ptr &response)
            {
                // 此处代码可能有更好的解决方法, yym 20200303
                REQ req = getProtobufMessage<REQ>(request);
                RES res; // = RES::default_instance();
                rep_cb_(req, res);
                std::string msg_str;
                res.SerializeToString(&msg_str);
                response = std::make_shared<bytes_vec>(msg_str.data(), msg_str.data() + msg_str.length());
            }
        private:
            std::function<void(const REQ&, RES&)> rep_cb_;
    };
}
}
#endif //_RECEIVE_CALLBACK_H_